home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / interapplication comm / finderdragpro / fdputilities.c next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  14.3 KB  |  447 lines

  1. /*
  2.     File:        FDPUtilities.c
  3.     
  4.     Description:     utilities used in FinderDragPro.c.  Routines in this file are used in the
  5.                 FinderDragPro.c file;  however, since they are not directly related
  6.                 to the example, they have been moved here to simplify the main file.
  7.  
  8.     Author:        John Montbriand
  9.  
  10.     Copyright:     Copyright: © 1999 by Apple Computer, Inc.
  11.                 all rights reserved.
  12.     
  13.     Disclaimer:    You may incorporate this sample code into your applications without
  14.                 restriction, though the sample code has been provided "AS IS" and the
  15.                 responsibility for its operation is 100% yours.  However, what you are
  16.                 not permitted to do is to redistribute the source as "DSC Sample Code"
  17.                 after having made changes. If you're going to re-distribute the source,
  18.                 we require that you make it clear in the source that the code was
  19.                 descended from Apple Sample Code, but that you've made changes.
  20.     
  21.     Change History (most recent first):
  22.     9/9/99 created by John Montbriand
  23. */
  24.  
  25. #include "FDPUtilities.h"
  26. #include <QuickDraw.h>
  27. #include <Gestalt.h>
  28. #include <Palettes.h>
  29. #include <Threads.h>
  30. #include <fp.h>
  31.  
  32.  
  33.  
  34. /* ValidFSSpec verifies that *spec refers is formatted correctly, and it
  35.     verifies that it refers to an existing file in an existing directory on
  36.     and existing volume. If *spec is valid, the function returns noErr,
  37.     otherwise an error is returned. */
  38. OSErr ValidFSSpec(FSSpec *spec) {
  39.     FInfo fndrInfo;
  40.         /* check the name's size */
  41.     if (spec->name[0] + (sizeof(FSSpec) - sizeof(spec->name)) > sizeof(FSSpec)) return paramErr;
  42.         /* ckeck if it refers to a file */
  43.     return FSpGetFInfo(spec, &fndrInfo);
  44. }
  45.  
  46.  
  47. /* ResolveAliasQuietly resolves an alias using a fast search with no user interaction.  Our main loop
  48.     periodically resolves gFileAlias comparing the result to gTargetFile to keep the display up to date.
  49.     As a result, we would like the resolve alias call to be as quick as possible AND since the application
  50.     may be in the background when  it is called, we don't want any user interaction. */
  51. OSErr ResolveAliasQuietly(ConstFSSpecPtr fromFile, AliasHandle alias, FSSpec *target, Boolean *wasChanged) {
  52.     short aliasCount;
  53.     Boolean needsUpdate;
  54.     OSErr err;
  55.         /* set up locals */
  56.     aliasCount = 1;
  57.     needsUpdate = false;
  58.     *wasChanged = false;
  59.         /* call MatchAlias to resolve the alias.  
  60.             kARMNoUI = no user interaction,
  61.             kARMSearch = do a fast search. */
  62.     err = MatchAlias(NULL, (kARMNoUI | kARMSearch), alias, &aliasCount, target, &needsUpdate, NULL, NULL);
  63.     if (err == noErr) {
  64.             /* if the alias was changed, update it. */
  65.         err = UpdateAlias(fromFile, target, alias, wasChanged);
  66.     }
  67.     return err;
  68. }
  69.  
  70.  
  71.  
  72. /* MakeHFSFlavorFromAlias converts an alias handle into a HFSFlavor
  73.     structure filling in the fields with their correct values. */
  74. OSErr MakeHFSFlavorFromAlias(AliasHandle theAlias, HFSFlavor *theFlavor) {
  75.     OSErr err = noErr;
  76.     Boolean wasChanged;
  77.     CInfoPBRec cat;
  78.     
  79.         /* resolve the alias with no user interaction.  Do a fast search. */
  80.     err = ResolveAliasQuietly(NULL, theAlias, &theFlavor->fileSpec, &wasChanged);
  81.     if (err != noErr) return err;
  82.     
  83.         /* pull some information about the file */
  84.     cat.hFileInfo.ioNamePtr = theFlavor->fileSpec.name;
  85.     cat.hFileInfo.ioVRefNum = theFlavor->fileSpec.vRefNum;
  86.     cat.hFileInfo.ioDirID = theFlavor->fileSpec.parID;
  87.     cat.hFileInfo.ioFDirIndex = 0;
  88.     err = PBGetCatInfoSync(&cat);
  89.     if (err != noErr) return err;
  90.     
  91.         /* save the finder flags */
  92.     theFlavor->fdFlags = cat.hFileInfo.ioFlFndrInfo.fdFlags;
  93.  
  94.         /* calculate the type and creator */
  95.     if (theFlavor->fileSpec.parID == fsRtParID) {
  96.             /* volumes have parrent id == 1 */
  97.         theFlavor->fileCreator = 'MACS';
  98.         theFlavor->fileType = 'disk';
  99.     } else if ((cat.hFileInfo.ioFlAttrib & ioDirMask) != 0) {
  100.             /* directories have bit 4 set in the attributes */
  101.         theFlavor->fileCreator = 'MACS';
  102.         theFlavor->fileType = 'fold';
  103.     } else {
  104.             /* assume anything else is a file */
  105.         theFlavor->fileCreator = cat.hFileInfo.ioFlFndrInfo.fdCreator;
  106.         theFlavor->fileType = cat.hFileInfo.ioFlFndrInfo.fdType;
  107.     }
  108.     
  109.         /* done */
  110.     return noErr;
  111. }
  112.  
  113.  
  114.  
  115.  
  116.  
  117. /* IconsToMaskedPixMap converts either an IconServices icon reference or a IconUtilities icon suite into a
  118.     (GWorldPtr, RgnHandle) pair appropriate for dragging as a transparent icon image.  if iconReference
  119.     then calls to IconServices are made, if iconSuite is not null, then calls to icon services are made. 
  120.     The resulting graphics world and region handle are returned in *imageGWorld and *maskRgn. */
  121. OSErr IconsToMaskedPixMap(const Rect *iconRect, Handle iconSuite, IconRef iconReference,
  122.                     GWorldPtr *imageGWorld, RgnHandle *maskRgn) {
  123.     OSErr err;
  124.     GWorldPtr theWorld;
  125.     RgnHandle theMask;
  126.     Rect imageRect;
  127.     Point offsetPt;
  128.     GDHandle saveDevice;
  129.     CGrafPtr savePort;
  130.     PixMapHandle imagePixMap;
  131.     
  132.         /* set up locals */
  133.     theWorld = NULL;
  134.     theMask = NULL;
  135.     imageRect = *iconRect;
  136.     OffsetRect(&imageRect, -imageRect.left, -imageRect.top);
  137.     LocalToGlobal(&offsetPt);
  138.         
  139.         /* create the graphics world */
  140.     err = NewGWorld(&theWorld, 8, &imageRect, NULL, NULL, 0);
  141.     if (err != noErr) goto bail;
  142.     if (theWorld == NULL) { err = memFullErr; goto bail; } /* often missed... */
  143.     
  144.         /* set up the mask region */
  145.     theMask = NewRgn();
  146.     if (theMask == NULL) { err = memFullErr; goto bail; }
  147.     
  148.         /* calculate the icon's mask region */
  149.     if (iconReference != NULL)
  150.         err = IconRefToRgn(theMask, &imageRect, kAlignNone, kIconServicesNormalUsageFlag, iconReference);
  151.     else if (iconSuite != NULL)
  152.         err = IconSuiteToRgn(theMask, &imageRect, kAlignNone, iconSuite);
  153.     else err = paramErr;
  154.     if (err != noErr) goto bail;
  155.     
  156.         /* set up the drawing environment */
  157.     GetGWorld (&savePort, &saveDevice);
  158.     LockPixels((imagePixMap = GetGWorldPixMap(theWorld)));
  159.     SetGWorld(theWorld, NULL);
  160.     
  161.         /* draw the icon suite */
  162.     EraseRect(&imageRect);
  163.     if (iconReference != NULL)
  164.         err = PlotIconRef(&imageRect, kAlignNone, kTransformNone, kIconServicesNormalUsageFlag, iconReference);
  165.     else err = PlotIconSuite(&imageRect, kAlignNone, kTransformNone, iconSuite);
  166.     
  167.         /* restore the drawing environment */
  168.     SetGWorld(savePort, saveDevice);
  169.     UnlockPixels(imagePixMap);
  170.     
  171.         /* after restoring, check drawing result */
  172.     if (err != noErr) goto bail;
  173.     
  174.         /* store what we created. */
  175.     *imageGWorld = theWorld;
  176.     *maskRgn = theMask;
  177.     return noErr;
  178. bail:
  179.     if (theWorld != NULL) DisposeGWorld(theWorld);
  180.     if (theMask != NULL) DisposeRgn(theMask);
  181.     return err;
  182. }
  183.  
  184.  
  185. /* GrayOutBox grays out an area of the screen in the current grafport.  
  186.     *theBox is in local coordinates in the current grafport. This routine
  187.     is for direct screen drawing only.  */
  188. void GrayOutBox(Rect *theBox) {
  189.     long response;
  190.     Rect globalBox;
  191.     GDHandle maxDevice;
  192.     RGBColor rgbWhite = {0xFFFF, 0xFFFF, 0xFFFF}, rgbBlack = {0, 0, 0}, sForground, sBackground;
  193.     PenState penSave;
  194.         /* save the current drawing state */
  195.     GetPenState(&penSave);
  196.         /* if no color quickdraw, fail...*/
  197.     if (Gestalt(gestaltQuickdrawVersion, &response) != noErr) response = 0;
  198.     if (response >= gestalt8BitQD) {
  199.             /* get the device for the rectangle */
  200.         globalBox = *theBox;
  201.         LocalToGlobal((Point*) &globalBox.top);
  202.         LocalToGlobal((Point*) &globalBox.bottom);
  203.         maxDevice = GetMaxDevice(&globalBox);
  204.         if (maxDevice != NULL) {
  205.                 /* calculate the best gray */
  206.             if ( GetGray(maxDevice, &rgbWhite, &rgbBlack)) {
  207.                     /* draw over the area in gray using addMax transfer mode */
  208.                 GetForeColor(&sForground);
  209.                 GetBackColor(&sBackground);
  210.                 RGBForeColor(&rgbBlack);
  211.                 RGBBackColor(&rgbWhite);
  212.                 PenMode(addMax);
  213.                 PaintRect(theBox);
  214.                 RGBForeColor(&sForground);
  215.                 RGBBackColor(&sBackground);
  216.                     /* restore the pen state and leave */
  217.                 SetPenState(&penSave);
  218.                 return;
  219.             }
  220.         }
  221.     }
  222.         /* fall through to using the gray pattern */
  223.     PenPat(&qd.gray);
  224.     PenMode(notPatBic);
  225.     PaintRect(theBox);
  226.     SetPenState(&penSave);
  227. }
  228.  
  229.  
  230. /* ShowDragHiliteBox is called to hilite the drop box area in the
  231.     main window.  Here, we draw a 3 pixel wide border around *boxBounds.  */
  232. OSErr ShowDragHiliteBox(DragReference theDragRef, Rect *boxBounds) {
  233.     RgnHandle boxRegion, insetRegion;
  234.     OSErr err;
  235.     Rect box;
  236.         /* set up locals */
  237.     boxRegion = insetRegion = NULL;
  238.         /* create the region */
  239.     if ((boxRegion = NewRgn()) == NULL) { err = memFullErr; goto bail; }
  240.     if ((insetRegion = NewRgn()) == NULL) { err = memFullErr; goto bail; }
  241.     box = *boxBounds;
  242.     InsetRect(&box, -5, -5);
  243.     RectRgn(boxRegion, &box);
  244.     InsetRect(&box, 3, 3);
  245.     RectRgn(insetRegion, &box);
  246.     DiffRgn(boxRegion, insetRegion, boxRegion);
  247.         /* hilite the region */
  248.     err = ShowDragHilite(theDragRef, boxRegion, true);
  249. bail:
  250.         /* clean up and leave */
  251.     if (boxRegion != NULL) DisposeRgn(boxRegion);
  252.     if (insetRegion != NULL) DisposeRgn(insetRegion);
  253.     return err;
  254. }
  255.  
  256.  
  257.  
  258.  
  259.  
  260. /* CopyCommandParam includes the parameters used for a copy
  261.     operation.  A record of this type is created in the CopyFileCmd routine,
  262.     and a pointer to it is passed to a Thread Manager task that does
  263.     the actual copy. */
  264. typedef struct {
  265.     FSSpec src, dst;
  266.     short srcRef, dstRef;
  267.     unsigned long total, number;
  268.     CopyCallback callback;
  269.     CopyErrorHandler errorhandler;
  270.     ThreadID copythread;
  271.     Ptr copyBuffer;
  272. } CopyCommandParam, *CopyCmdParamPtr;
  273.  
  274.  
  275. CopyCmdParamPtr gCopyParam = NULL;
  276.  
  277. /* CopyFileInProgress returns true if a copy command is in
  278.     progress.  In this implementation, it simply checks to see
  279.     if gCopyParam is not NULL. */
  280. Boolean CopyFileInProgress(void) {
  281.     return (gCopyParam != NULL);
  282. }
  283.  
  284. /* AbortCopyOperation aborts an ongoing copy operation.  this routine
  285.     deallocates any structures allocated and deletes the target file.  It
  286.     also tears down the thread. */
  287. void AbortCopyOperation(void) {
  288.     if (gCopyParam != NULL) {
  289.         gCopyParam->errorhandler(&gCopyParam->src, userCanceledErr);
  290.         gCopyParam->callback(&gCopyParam->src, kCopyEnd, 100);
  291.         DisposeThread(gCopyParam->copythread, 0, false);
  292.         if (gCopyParam->copyBuffer != NULL)
  293.             DisposePtr((Ptr) gCopyParam->copyBuffer);
  294.         if (gCopyParam->srcRef != 0) FSClose(gCopyParam->srcRef);
  295.         if (gCopyParam->dstRef != 0) FSClose(gCopyParam->dstRef);
  296.         FSpDelete(&gCopyParam->dst);
  297.         DisposePtr((Ptr) gCopyParam);
  298.         gCopyParam = NULL;
  299.     }
  300. }
  301.  
  302.  
  303. /* CopyForkOperation copies forkLength bytes from the source file to the destination
  304.     file using (buffer, bufferSize) as a data buffer during the copy.  As the copy proceeds,
  305.     the value of gBytesCopied is updated to indicate the total number of bytes copied. */
  306. static OSErr CopyForkOperation(CopyCmdParamPtr param, long forkLength) {
  307.     long bytecount, count, percent;
  308.     OSErr err;
  309.     
  310.     bytecount = 0;
  311.     while (bytecount < forkLength) {
  312.         count = forkLength - bytecount;
  313.         if (count > kCopyBufferSize) count = kCopyBufferSize;
  314.         
  315.         err = FSRead(param->srcRef, &count, param->copyBuffer);
  316.         if (err != noErr) return err;
  317.         YieldToAnyThread();
  318.         
  319.         err = FSWrite(param->dstRef, &count, param->copyBuffer);
  320.         if (err != noErr) return err;
  321.         YieldToAnyThread();
  322.             
  323.         bytecount += count;
  324.         param->number += count;
  325.         if (param->total == 0)
  326.             percent = 100;
  327.         else percent = rinttol((((float) param->number) / ((float) param->total)) * 100.0);
  328.         param->callback(¶m->src, kCopyRun, percent);
  329.         YieldToAnyThread();
  330.  
  331.     }
  332.     return noErr;
  333. }
  334.  
  335. /* CopyCommandThread is a Thread Manager task that completes a copy operation.
  336.     The task is started in the CopyFileCmd routine.   */
  337. static pascal void* CopyCommandThread(void *threadParam) {
  338.     CopyCmdParamPtr param;
  339.     CInfoPBRec cat;
  340.     OSErr err;
  341.         /* set up */
  342.     param = (CopyCmdParamPtr) threadParam;
  343.     YieldToAnyThread();
  344.         /* calculate the total bytes */
  345.     cat.hFileInfo.ioNamePtr = param->src.name;
  346.     cat.hFileInfo.ioVRefNum = param->src.vRefNum;
  347.     cat.hFileInfo.ioDirID = param->src.parID;
  348.     cat.hFileInfo.ioFDirIndex = 0;
  349.     err = PBGetCatInfoSync(&cat);
  350.     if (err != noErr) goto bail;
  351.     if ((cat.hFileInfo.ioFlAttrib & ioDirMask) != 0) {
  352.         err = kCannotCopyDirError;
  353.         goto bail;
  354.     }
  355.     param->total = cat.hFileInfo.ioFlLgLen + cat.hFileInfo.ioFlRLgLen;
  356.     
  357.         /* file created, switch out */
  358.     YieldToAnyThread();
  359.  
  360.         /* allocate the copy buffer */
  361.     param->copyBuffer = NewPtr(kCopyBufferSize);
  362.     if (param->copyBuffer == NULL) { err = memFullErr; goto bail; }
  363.  
  364.         /* copy the data fork, if there is one */
  365.     if (cat.hFileInfo.ioFlLgLen > 0) {
  366.         err = FSpOpenDF(¶m->src, fsRdPerm, ¶m->srcRef);
  367.         if (err != noErr) goto bail;
  368.         err = FSpOpenDF(¶m->dst, fsWrPerm, ¶m->dstRef);
  369.         if (err != noErr) goto bail;
  370.         err = CopyForkOperation(param, cat.hFileInfo.ioFlLgLen);
  371.         if (err != noErr) goto bail;
  372.         FSClose(param->srcRef);
  373.         param->srcRef = 0;
  374.         FSClose(param->dstRef);
  375.         param->dstRef = 0;
  376.     }
  377.         /* copy the resource fork, if there is one */
  378.     if (cat.hFileInfo.ioFlRLgLen > 0) {
  379.         err = FSpOpenRF(¶m->src, fsRdPerm, ¶m->srcRef);
  380.         if (err != noErr) goto bail;
  381.         err = FSpOpenRF(¶m->dst, fsWrPerm, ¶m->dstRef);
  382.         if (err != noErr) goto bail;
  383.         err = CopyForkOperation(param, cat.hFileInfo.ioFlRLgLen);
  384.         if (err != noErr) goto bail;
  385.         FSClose(param->srcRef);
  386.         param->srcRef = 0;
  387.         FSClose(param->dstRef);
  388.         param->dstRef = 0;
  389.     }
  390.         /* flush the destination volume */
  391.     FlushVol(NULL, param->dst.vRefNum);    /* err = best effort */ 
  392.         /* clean up */
  393.     param->callback(¶m->src, kCopyEnd, 100);
  394.     DisposePtr(param->copyBuffer);
  395.     param->copyBuffer = NULL;
  396.     DisposePtr((Ptr) param);
  397.     gCopyParam = NULL;
  398.     return NULL;
  399. bail:
  400.     param->errorhandler(¶m->src, err);
  401.     param->callback(¶m->src, kCopyEnd, 100);
  402.     if (param->srcRef != 0) FSClose(param->srcRef);
  403.     if (param->dstRef != 0) FSClose(param->dstRef);
  404.     if (param->copyBuffer != NULL) DisposePtr(param->copyBuffer);
  405.     FSpDelete(¶m->dst);
  406.     DisposePtr((Ptr) param);
  407.     gCopyParam = NULL;
  408.     return NULL;
  409. }
  410.  
  411. OSErr CopyFileCmd(FSSpec *theSource, FSSpec *theTarget, CopyCallback callback, CopyErrorHandler errorhandler) {
  412.     CopyCmdParamPtr param;
  413.     OSErr err;
  414.     Boolean threadCreated;
  415.         /* set up locals */
  416.     threadCreated = true;
  417.     param = NULL;
  418.         /* check copy conditions */
  419.     if (gCopyParam != NULL) return kCopyNotRentrantError;
  420.         /* set up param */
  421.     param = (CopyCmdParamPtr) NewPtr(sizeof(CopyCommandParam));
  422.     if (param == NULL) { err = memFullErr; goto bail; }
  423.     param->src = *theSource;
  424.     param->dst = *theTarget;
  425.     param->srcRef = 0;
  426.     param->dstRef = 0;
  427.     param->total = param->number = 0;
  428.     param->callback = callback;
  429.     param->errorhandler = errorhandler;
  430.     param->copyBuffer = NULL;
  431.         /* create a thread */
  432.     err = NewThread(kCooperativeThread, CopyCommandThread, param, 0, kCreateIfNeeded, NULL, ¶m->copythread);
  433.     if (err != noErr) goto bail;
  434.     threadCreated = true;
  435.     gCopyParam = param;
  436.     callback(¶m->src, kCopyStart, 0);
  437.     return noErr;
  438. bail:
  439.     if (threadCreated)
  440.         DisposeThread(param->copythread, 0, false);
  441.     if (param != NULL) DisposePtr((Ptr) param);
  442.     return err;
  443. }
  444.  
  445.  
  446.  
  447.